package net.lb.socketclient.listen;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.CompletionHandler;
import java.nio.channels.InterruptedByTimeoutException;
import net.lb.baseutil.collection.ByteBufferPool;
import net.lb.baseutil.collection.ByteCache;
import net.lb.baseutil.collection.ByteCachePool;
import net.lb.socketserver.exception.LessThanProtocolException;
import net.lb.socketserver.exception.NotFitProtocolException;
import net.lb.socketserver.exception.NotIntactDataException;
import net.lb.socketserver.util.CheckReadBuffer;
import net.lb.socketserver.util.HeadFactory;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class ClientReadHandler implements CompletionHandler<Integer, ClientChannelInfo>
{
    private static Logger logger = LogManager.getLogger();
    private HeadFactory   headFactory;
    
    public ClientReadHandler(HeadFactory headFactory)
    {
        this.headFactory = headFactory;
    }
    
    @Override
    public void completed(Integer result, ClientChannelInfo channelInfo)
    {
        if (result == -1)
        {
            channelInfo.close();
            return;
        }
        ByteBuffer readBuffer = channelInfo.getReadBuffer();
        readBuffer.flip();
        while (true)
        {
            try
            {
                buildMessageAndSend(readBuffer, channelInfo);
            }
            catch (NotFitProtocolException e)
            {
                logger.debug("协议错误，关闭链接");
                channelInfo.close();
                return;
            }
            catch (LessThanProtocolException e)
            {
                readBuffer.compact();
                channelInfo.startReadWait();
                return;
            }
            catch (NotIntactDataException e)
            {
                logger.debug("扩展容量，继续读取");
                readBuffer.compact();
                readBuffer = ByteBufferPool.expandToSize(e.getNeedSize(), readBuffer);
                channelInfo.setReadBuffer(readBuffer);
                channelInfo.continueRead();
                return;
            }
        }
    }
    
    private void buildMessageAndSend(ByteBuffer readBuffer, ClientChannelInfo channelInfo) throws NotFitProtocolException, LessThanProtocolException, NotIntactDataException
    {
        int length = CheckReadBuffer.checkReadBuffer(readBuffer, headFactory);
        readBuffer.position(readBuffer.position() + 4);
        byte command = readBuffer.get();
        byte result = readBuffer.get();
        readBuffer.position(readBuffer.position() + 4);
        ByteCache cache = ByteCachePool.get();
        cache.putByteBuffer(readBuffer, length);
        readBuffer.position(readBuffer.position() + length);
        channelInfo.handleResult(cache, command, result);
        ByteCachePool.returnCache(cache);
    }
    
    @Override
    public void failed(Throwable exc, ClientChannelInfo clientChannelInfo)
    {
        clientChannelInfo.close();
        if (exc instanceof ClosedChannelException)
        {
            logger.debug("通道{}关闭", clientChannelInfo.getAddress());
            
        }
        else if (exc instanceof InterruptedByTimeoutException)
        {
            logger.debug("通道{}读取超时时间到达，关闭", clientChannelInfo.getAddress());
        }
        else if (exc instanceof IOException)
        {
            String msg = exc.getMessage();
            if (msg.startsWith("指定的网络名不再可用") || msg.startsWith("远程主机强迫关闭了一个现有的连接"))
            {
                logger.debug("socket关闭");
            }
            else
            {
                logger.error("未知的io错误", exc);
            }
        }
        else
        {
            logger.debug("未知异常", exc);
        }
        clientChannelInfo.handleException(exc);
    }
}
